package com.thientan.controller

import grails.converters.JSON

import java.text.SimpleDateFormat

import org.hibernate.criterion.CriteriaSpecification
import org.hibernate.transform.Transformers

import com.thientan.export.ExportType
import com.thientan.model.ChiTietThuChi
import com.thientan.model.HopDong
import com.thientan.model.enums.LoaiChiTietThuChi
import com.thientan.model.enums.TrangThaiHopDong
import com.thientan.service.HopDongService
import com.thientan.service.InKhachHangService
import com.thientan.service.InMaVachService
import com.thientan.service.TimHopDongService
import com.thientan.utils.Constants
import com.thientan.utils.Utility

class TimHopDongController extends HopDongController {

	static final int MAXIMUM_MAVACH_PAGE = 15
	TimHopDongService timHopDongService
	InMaVachService inMaVachService
	InKhachHangService inKhachHangService
	HopDongService hopDongService

	@Override
	public Object getDomainService() {
		timHopDongService
	}

	@Override
	protected String getExportFileName(){
		"DanhSachHopDong"
	}

	@Override
	protected ExportType getExportType(){
		ExportType.XLS
	}

	private List<String> getRenderedProps() {
		[
			"maHd",
			"maDt",
			"maTn",
			"maNv1",
			"maNv2",
			"khHoTen",
			"trangThaiText",
			"giaTri",
			"tienTraTruoc",
			"tienDaThu",
			"tienConLai"
		]
	}

	private List<String> getMorePropsForExport() {
		[
			"id",
			"khDchi",
			"khDt",
			"khPxa",
			"khQhuyen",
			"khTpho",
			"ngayBanText",
			"tienGiamGia",
			"liDoGiamGia",
			"maNvCapNhat",
			"ngayCapNhatText"
		]
	}

	@Override
	protected Map buildExportData(Map exportParams) {
		def sdfDateTo = new java.text.SimpleDateFormat(Constants.DEFAULT_DATE_FORMAT)
		List hds = doQuery()
		if (!hds) {
			return ["data" : null,
				"tongSoHd" : "0",
				"ngayXuat" : sdfDateTo.format(new Date()),
				"thoiGian" : ""]
		}
		Map relatedData = getRelatedChiTietThuChi(hds*.id)
		List hdData =  extractPropertiesAsMapsWithOrderNumber(hds, renderedProps + morePropsForExport, false)
		hdData = hdData.collect {
			Long hdId = it["id"]
			Map additionalMap = ["denDt" : 0, "denNv" : 0, "denCty" : 0, "tienTraKhach" : 0, "tienKhauHao" : 0]
			if (relatedData.get(hdId)) {
				List chiTiets = relatedData.get(hdId)
				chiTiets.each {
					Double value = it[2] != null ? it[2] : 0
					switch (it[1]) {
						case LoaiChiTietThuChi.DEN_DT:
							additionalMap["denDt"] = value
							break
						case LoaiChiTietThuChi.DEN_NV:
							additionalMap["denNv"] = additionalMap["denNv"] + value
							break
						case LoaiChiTietThuChi.DEN_CTY:
							additionalMap["denCty"] = value
							break
						case LoaiChiTietThuChi.TRA_KHACH:
							additionalMap["tienTraKhach"] = value
							break
						case LoaiChiTietThuChi.KHAU_HAO:
							additionalMap["tienKhauHao"] = value
							break
						default:
							break
					}
				}
			}
			it + additionalMap
		}

		def sdfToDate = new java.text.SimpleDateFormat(Constants.TO_DATE_FORMAT)
		String fromDate = params.ngayBanFrom ? sdfDateTo.format(sdfToDate.parse(params.ngayBanFrom)) : ""
		String toDate = params.ngayBanTo ? sdfDateTo.format(sdfToDate.parse(params.ngayBanTo)) :
				message(code : "default.thientan.messages.now", args : null)
		return ["data" : hdData,
			"tongSoHd" : hds.size().toString(),
			"ngayXuat" : sdfDateTo.format(new Date()),
			"thoiGian" : fromDate + " - " + toDate]
	}

	def search = {
		def hds = doQuery() // hds here is a PagedResultList instance
		Map data = listAsMap(extractPropertiesAsMapsWithOrderNumber(hds, renderedProps))
		data.putAt("count", hds.totalCount)
		render data as JSON
	}

	private Map getRelatedChiTietThuChi(List hdIds) {
		List cttcs = ChiTietThuChi.withCriteria {
			projections {
				property("hopDong.id")
				property("loaiChiTiet")
				property("soTien")
			}
			'in'("hopDong.id", hdIds)
		}
		Map result = [:]
		cttcs.each {
			Long hdId = it[0]
			List existData = result.get(hdId)
			if (existData) {
				existData << it
				result.put(hdId, existData)
			} else {
				result.put(hdId, [it])
			}
		}
		result
	}

	private def doQuery() {
		boolean isExport = actionName == "export"
		def criteria = isExport ? params : JSON.parse(params["criteria"])
		def hds = HopDong.createCriteria().list(max : (params["max"] ? params.int('max') : null),
				offset : ( params["offset"] ? params.int('offset') : null)) {
					createAlias("khachHang", "kh", CriteriaSpecification.INNER_JOIN)
					createAlias("nvDoiTruong", "dt", CriteriaSpecification.LEFT_JOIN)
					createAlias("nvBan1", "nv1", CriteriaSpecification.INNER_JOIN)
					createAlias("nvBan2", "nv2", CriteriaSpecification.INNER_JOIN)
					createAlias("nvThuNgan", "tn", CriteriaSpecification.LEFT_JOIN)
					if (isExport) {
						createAlias("auditingInfo.nvCapNhat", "nvCapNhat")
					}

					projections {
						if (params["isChangeThuNgan"] || params["isDongHd"] || params["isXuatHd"]) {
							property("id")
						} else {
							property("maHd", "maHd")
							property("dotBan", "dotBan")
							property("dt.maNv", "maDt")
							property("tn.maNv", "maTn")
							property("nv1.maNv", "maNv1")
							property("nv2.maNv", "maNv2")
							property("kh.hoTen", "khHoTen")
							property("trangThai", "trangThai")
							property("giaTri", "giaTri")
							property("tienTraTruoc", "tienTraTruoc")
							property("tienDaThu", "tienDaThu")
							property("tienConLai", "tienConLai")
							if (isExport) {
								property("id", "id")
								property("kh.diaChi", "khDchi")
								property("kh.dienThoai", "khDt")
								property("kh.phuongXa", "khPxa")
								property("kh.quanHuyen", "khQhuyen")
								property("kh.tinhThanh", "khTpho")
								property("ngayBan", "ngayBan")
								property("tienGiamGia", "tienGiamGia")
								property("liDoGiamGia", "liDoGiamGia")
								property("nvCapNhat.maNv", "maNvCapNhat")
								property("auditingInfo.ngayCapNhat", "ngayCapNhat")
							}
						}
					}

					if (criteria["maHd"]) {
						like("maHd", criteria["maHd"])
					}
					if (criteria["dotBan"]) {
						eq("dotBan", Integer.valueOf(criteria["dotBan"]))
					}

					if (criteria["nvDoiTruong-id"] == "NO_DT") {
						isNull("nvDoiTruong")
					} else if (criteria["nvDoiTruong-id"]) {
						eq("nvDoiTruong.id", Long.valueOf(criteria["nvDoiTruong-id"]))
					}

					if (criteria["nvBan-id"]) {
						or {
							eq("nvBan1.id", Long.valueOf(criteria["nvBan-id"]))
							eq("nvBan2.id", Long.valueOf(criteria["nvBan-id"]))
						}
					}

					if (criteria["nvThuNgan-id"] == "CTY") {
						isNull("nvThuNgan")
					} else if (criteria["nvThuNgan-id"]) {
						eq("nvThuNgan.id", Long.valueOf(criteria["nvThuNgan-id"]))
					}

					if (criteria["ngayBanFrom"]) {
						ge("ngayBan", new SimpleDateFormat(Constants.TO_DATE_FORMAT).parse(criteria["ngayBanFrom"]))
					}

					if (criteria["ngayBanTo"]) {
						le("ngayBan", new SimpleDateFormat(Constants.TO_DATE_FORMAT).parse(criteria["ngayBanTo"]))
					}

					if (criteria["kh-hoTen"]) {
						ilike("kh.hoTen", "%" + criteria["kh-hoTen"] + "%")
					}

					if (criteria["tinhThanh"]) {
						eq("kh.tinhThanh", criteria["tinhThanh"])
					}

					if (criteria["quanHuyen"]) {
						eq("kh.quanHuyen", criteria["quanHuyen"])
					}

					if (criteria["phuongXa"]) {
						eq("kh.phuongXa", criteria["phuongXa"])
					}

					if(Boolean.valueOf(criteria["daGiaoPhieu"]) == true){
						isNotNull("daGiaoPhieu")
					} else {
						isNull("daGiaoPhieu")
					}

					if (criteria["trangThai"]) {
						eq("trangThai", TrangThaiHopDong.valueOf(criteria["trangThai"]))
					} else {
						ne("trangThai", TrangThaiHopDong.DONG) // always exclude contracts whose status is 'DONG' if not specify explicitly
					}

					order("nvDoiTruong.id")
					order("prefixMaHd")
					order("soHd")

					if (!params["isChangeThuNgan"] && !params["isDongHd"] && !params["isXuatHd"]) {
						resultTransformer(Transformers.aliasToBean(HopDong.class))
					}
				}
		hds
	}

	def changeThuNgan = {
		List<Long> ids = doQuery()

		Map result = [:]
		def idThuNgan = params["idThuNgan"]
		if (idThuNgan == "CTY") {
			idThuNgan = null
		}
		try {
			int numHd = HopDong.executeUpdate("update HopDong hd set hd.nvThuNgan.id = ${idThuNgan} where id in (:ids)", [ids : ids])
			result = [success : true, numOfHd : numHd]
		} catch (Exception e) {
			log.error("Error occurred when assigning casher to contract: ", e)
			result = [success : false]
		}
		render result as JSON
	}

	def dongHd = {
		List<Long> ids = doQuery()

		Map result = [:]
		try {
			Long hdDangGop = HopDong.countByIdInListAndTrangThai(ids, TrangThaiHopDong.DANG_TRA_GOP)
			if (hdDangGop == 0) {
				int numHd = HopDong.executeUpdate("update HopDong hd set hd.trangThai = '${TrangThaiHopDong.DONG.value}' " +
						"where hd.id in (:ids) and hd.trangThai <> '${TrangThaiHopDong.DANG_TRA_GOP.value}'", [ids : ids])
				result = [success : true, numOfHd : numHd]
			} else {
				result = [success : false, numOfHd : hdDangGop]
			}
		} catch (Exception e) {
			log.error("Error occurred when closing contracts: ", e)
			result = [success : false]
		}
		render result as JSON
	}

	def giaoPhieuThu = {
		List<Long> ids = doQuery()

		Map result = [:]
		try {
			Long daGiaoPt = HopDong.countByIdInListAndDaGiaoPhieuNotEqual(ids, null)
			if (daGiaoPt == 0) {
				Long numHd = timHopDongService.giaoPhieuThu(ids)
				result = [success : true, numOfHd : numHd]
			} else {
				result = [success : false, numOfHd : daGiaoPt]
			}
		} catch (Exception e) {
			log.error("Error occurred when closing contracts: ", e)
			result = ["success" : false]
		}
		render result as JSON
	}

	def exportMultiFiles = {
		List<Long> ids = doQuery()
		String type = params["type"]
		Map result = [:]

		try {
			// Build file name
			String timeInstance = new SimpleDateFormat(Constants.DATETIME_EXPORT).format(Calendar.instance.time)
			// Set base path to store the exported file
			String basePath = "${realPath}exported${slash}${type}${timeInstance}${slash}"
			new File(basePath).mkdirs()
			if (type == "maVach") {
				String resourcePath = "${realPath}templates${slash}PhieuThuMaVachTheoNhom.jrxml"
				String emptyMaVach = "${realPath}templates${slash}MaVachEmpty.gif"
				List maVachs = HopDong.withCriteria {
					projections { property("maHd") }
					'in'("id", ids)
				}
				int i = 1;
				Map exportData = ['data' : []];
				int nhom = 1;
				maVachs.each {
					String barcodePath = "${basePath}maVach${it}.gif"
					Utility.generateBarcode(it, barcodePath)
					exportData.put("mavachpath${i}", barcodePath)
					i++;
					if(i > MAXIMUM_MAVACH_PAGE){
						Map exportParams = [
						                    "requestParams" : params,
						                    "fileName" : "MaVachTheoNhom${nhom}.pdf",
						                    "basePath" : basePath,
						                    "exportType" : ExportType.PDF
						                    ]
                		inMaVachService.export(exportData, exportParams['fileName'],
                				exportParams['basePath'], exportParams['exportType'], null, resourcePath)
						// Reset properties.
        				i = 1;
						nhom++;
						exportData = ['data' : []];
					}
				}
				// Print the last items
				if(i > 1 && i <= MAXIMUM_MAVACH_PAGE){
					Map exportParams = [
						"requestParams" : params,
						"fileName" : "MaVachTheoNhom${nhom}.pdf",
						"basePath" : basePath,
						"exportType" : ExportType.PDF
						]
					addMissingParameters(exportData, emptyMaVach);
					inMaVachService.export(exportData, exportParams['fileName'],
							exportParams['basePath'], exportParams['exportType'], null, resourcePath)
				}
				
			} else if (type == "khachHang") {
				String resourcePath = "${realPath}templates${slash}PhieuThuKhachHang.jrxml"
				List hds = HopDong.withCriteria {
					createAlias("khachHang", "kh")
					createAlias("nvDoiTruong", "dt")
					createAlias("nvBan1", "nv1")
					createAlias("nvBan2", "nv2")
					projections { 
						property("kh.hoTen")
						property("kh.diaChi")
						property("kh.phuongXa")
						property("kh.quanHuyen")
						property("kh.tinhThanh")
						property("kh.dienThoai")
						property("dt.maNv")
						property("nv1.maNv")
						property("nv2.maNv")
						property("giaTri")
						property("tienTraTruoc")
						property("maHd")
					}
					'in'("id", ids)
				}
				hds.each {
					String barcodePath = "${basePath}maVach${it[11]}.gif"
					Utility.generateBarcode(it[11], barcodePath)
					Map exportData = [	'data' : [],
						'ngayin' : printedCurrentDay,
						'tenkhachhang' : it[0],
						'diachi' : [it[1] ?: "", it[2]?: "", it[3]?: "", it[4]?: ""].join(", "),
						'dienthoai' : it[5] ?: "",
						'doitruong' : it[6] ?: "",
						'nv' : (it[7] ? it[7] + " + " : "") + (it[8] ?: ""),
						'conlai' : Utility.moneyFormat(it[9] - it[10]),
						'mavachpath' : barcodePath,
						'logopath' : realPath + logoPath
					]
					Map exportParams = [
								"requestParams" : params,
								"fileName" : "khachHang${it[11]}.pdf",
								"basePath" : basePath,
								"exportType" : ExportType.PDF
							]
					inKhachHangService.export(exportData, exportParams['fileName'],
							exportParams['basePath'], exportParams['exportType'], null, resourcePath)
				}
			} else {
				String resourcePath = "${realPath}templates${slash}PhieuThu.jrxml"
				List hds = HopDong.withCriteria {
					createAlias("khachHang", "kh")
					createAlias("nvDoiTruong", "dt")
					createAlias("nvBan1", "nv1")
					createAlias("nvBan2", "nv2")
					projections { 
						property("kh.hoTen")
						property("kh.diaChi")
						property("kh.phuongXa")
						property("kh.quanHuyen")
						property("kh.tinhThanh")
						property("kh.dienThoai")
						property("dt.maNv")
						property("nv1.maNv")
						property("nv2.maNv")
						property("giaTri")
						property("tienTraTruoc")
						property("maHd")
					}
					'in'("id", ids)
				}
				
				List phieuThuData = (1..24).collect{item ->
					['stt' : item,
					 'ngaytra' : "", 'tienthu' : "", 'tienconno' : "", 'khky' : "", 'tnky' : "", 'tenthungan' : ""
					]
				}
				hds.each {
					String barcodePath = "${basePath}maVach${it[11]}.gif"
					Utility.generateBarcode(it[11], barcodePath)
					
					Map exportData = [	'data' : phieuThuData,
						'ngayin' : printedCurrentDay,
						'tenkhachhang' : it[0],
						'diachi' : [it[1] ?: "", it[2]?: "", it[3]?: "", it[4]?: ""].join(", "),
						'dienthoai' : it[5] ?: "",
						'doitruong' : it[6] ?: "",
						'nv1' : it[7] ?: "",
						'nv2' : it[8] ?: "",
						'conlai' : Utility.moneyFormat(it[9] - it[10]),
						"mahopdong" : it[11],
						"tongtien" : Utility.moneyFormat(it[9] ?: 0),
						"tratruoc" : Utility.moneyFormat(it[10] ?: 0),
						'mavachpath' : barcodePath,
						'logopath' : realPath + logoPath
					]
					
					Map exportParams = [
								"requestParams" : params,
								"fileName" : "hopDong${it[11]}.pdf",
								"basePath" : basePath,
								"exportType" : ExportType.PDF
							]
					hopDongService.export(exportData, exportParams['fileName'],
							exportParams['basePath'], exportParams['exportType'], null, resourcePath)
				}
			}
			result = [success : true, numOfHd : ids.size(), folderName : "${type}${timeInstance}"]
		} catch(Exception e) {
			log.error("An error occurred when exporting file: ", e)
			result = [success : false]
		}
		render result as JSON
	}
	
	private void addMissingParameters(Map exportData, String defaultValue){
		for(int i = 1 ; i <= MAXIMUM_MAVACH_PAGE; i++){
			if(exportData.get("mavachpath${i}") == null){
				exportData.put("mavachpath${i}", defaultValue)
			}
		}
	}
}